use super::FILE_BLOCK_SIZE;
use crate::message::FileDataNetData;
use crate::utils::*;
use crate::APP_STATE;
use async_channel::{unbounded, Sender}; // 使用 async_channel 替代 crossbeam
use core::sync;
use dashmap::DashMap;
use std::fs;
use std::path::Path;
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
use std::time::Duration;
use std::{io, thread};
use tauri::async_runtime::spawn;
use tokio::fs::{File, OpenOptions};
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
use tokio::sync::Mutex;
// 定义一个结构体来存储文件信息
pub struct FileMeta {
    pub file_id: u32,
    pub file_name: String,
    pub file_size: u64,
}

impl FileMeta {
    pub fn clone_from(other: &FileMeta) -> FileMeta {
        FileMeta {
            file_id: other.file_id,
            file_name: other.file_name.clone(),
            file_size: other.file_size,
        }
    }
}

// file_manager内部维护的消息
#[derive(Debug)]
struct FileInfo {
    pub sync_point: u64,
    pub writer: Arc<FileWriter>,
    pub total_block_number: u64,
    pub written_block_number: AtomicU64,
}

pub struct FileManager {
    file_path: Arc<DashMap<u32, FileInfo>>,
    target_dir_path: String,
    writer_number: u32,
    sender: Option<Sender<FileDataNetData>>,
}

pub fn create_file_with_size(dir_path: &Path, file_name: &str, size: u64) -> io::Result<()> {
    let file_path = dir_path.join(file_name);
    let file = std::fs::File::create(file_path)?;
    file.set_len(size)?;
    Ok(())
}
#[derive(Debug, Clone)]
pub struct FileWriter {
    file: Arc<Mutex<File>>,
}

impl FileWriter {
    pub async fn new(path: &str) -> io::Result<Self> {
        let file = OpenOptions::new()
            .write(true)
            .create(true)
            .open(path)
            .await?;
        Ok(Self {
            file: Arc::new(Mutex::new(file)),
        })
    }

    pub async fn write_at(&self, offset: u64, data: Vec<u8>) -> io::Result<()> {
        let file = self.file.clone();
        let mut lock = file.lock().await;
        lock.seek(tokio::io::SeekFrom::Start(offset)).await?;
        lock.write_all(&data).await?;
        Ok(())
    }

    pub async fn close(&self) -> io::Result<()> {
        let mut lock = self.file.lock().await;
        lock.sync_all().await
    }
}

pub struct FileReader {
    file: Arc<Mutex<File>>,
}

impl FileReader {
    pub async fn new(path: &str) -> io::Result<Self> {
        let file = OpenOptions::new()
            .read(true)
            .open(path) // 注意这里去掉了create选项
            .await?;
        Ok(Self {
            file: Arc::new(Mutex::new(file)),
        })
    }

    pub async fn read_at(&self, offset: u64, length: usize) -> io::Result<Vec<u8>> {
        let file = self.file.clone();
        let mut lock = file.lock().await;

        // 定位到指定偏移量
        lock.seek(tokio::io::SeekFrom::Start(offset)).await?;

        // 读取数据（允许部分读取）
        let mut buf = vec![0; length];
        let bytes_read = lock.read(&mut buf).await?; // 返回实际读取的字节数

        // 截断缓冲区到实际读取的长度
        buf.truncate(bytes_read);
        Ok(buf)
    }
}

impl FileManager {
    pub fn new(target_dir_path: String, writer_number: u32) -> Self {
        let mut file_manager = FileManager {
            file_path: Arc::new(DashMap::new()),
            target_dir_path,
            writer_number,
            sender: None,
        };
        file_manager.init_manager();
        file_manager
    }

    pub fn check_exists_file(&self, file_id: u32) -> bool {
        self.file_path.contains_key(&file_id)
    }

    pub async fn add_file(
        &mut self,
        file_id: u32,
        file_name: String,
        file_size: u64,
    ) -> io::Result<()> {
        if self.check_exists_file(file_id) {
            return Ok(());
        }
        let dir_path = Path::new(&self.target_dir_path);
        create_file_with_size(dir_path, &file_name, file_size)?;
        let path = dir_path.join(file_name);
        let file_path = path
            .to_str()
            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "Invalid path"))?
            .to_string();

        // 当前文件的总块数
        let total_block_number = (file_size + FILE_BLOCK_SIZE - 1) / FILE_BLOCK_SIZE;
        // 同步点
        let sync_point = APP_STATE.sync_manager.generate_unique_sync_point().await;

        let file_info = FileInfo {
            sync_point: sync_point,
            writer: Arc::new(FileWriter::new(&file_path).await?),
            total_block_number: total_block_number,
            written_block_number: AtomicU64::new(0),
        };
        self.file_path.insert(file_id, file_info);
        Ok(())
    }

    pub async fn add_file_block(&self, file_block: FileDataNetData) -> io::Result<()> {
        if let Some(sender) = &self.sender {
            sender
                .send(file_block)
                .await
                .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("发送失败: {}", e)))
        } else {
            Err(io::Error::new(io::ErrorKind::Other, "写入通道未初始化"))
        }
    }

    pub async fn finish_file(&mut self, file_id: u32) {
        let store = self.file_path.clone();
        if let Some(entry) = store.get(&file_id) {
            let file_info = entry.value();
            let sync_point = file_info.sync_point;
            APP_STATE.sync_manager.wait_for_sync_point(sync_point).await;
        } else {
            eprintln!("文件ID {} 不存在", file_id);
        }
        if let Some(file_info) = self.file_path.remove(&file_id) {
            file_info.1.writer.close().await.expect("关闭文件失败");
        }
    }

    fn init_manager(&mut self) {
        let (sender, receiver) = unbounded::<FileDataNetData>(); // 创建 async_channel 的无界通道
        for _ in 0..self.writer_number {
            let receiver_clone = receiver.clone(); // 正确克隆 Receiver
            let store = self.file_path.clone();
            spawn(async move {
                while let Ok(data) = receiver_clone.recv().await {
                    // 异步接收
                    let offset = data.file_offset;
                    let file_id = data.file_id;
                    let file_data = data.file_data;
                    if let Some(entry) = store.get(&file_id) {
                        let file_info = entry.value();
                        if let Err(e) = file_info.writer.write_at(offset, file_data).await {
                            eprintln!("写入失败: {}", e);
                            continue;
                        }
                        file_info
                            .written_block_number
                            .fetch_add(1 as u64, std::sync::atomic::Ordering::SeqCst);
                        let val = file_info
                            .written_block_number
                            .load(std::sync::atomic::Ordering::SeqCst);
                        if val == file_info.total_block_number {
                            APP_STATE
                                .sync_manager
                                .release_sync_point(file_info.sync_point, 0 as u64)
                                .await;
                            println!("释放文件传输同步点");
                        }
                    } else {
                        eprintln!("文件ID {} 不存在", file_id);
                    }
                }
            });
        }
        self.sender = Some(sender);
    }

    pub fn get_file_info(file_path: &str) -> io::Result<FileMeta> {
        // 将文件路径转换为 Path
        let path = Path::new(file_path);

        // 获取文件名
        let file_name = path
            .file_name()
            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Invalid file path"))?
            .to_string_lossy()
            .into_owned();

        // 获取文件元数据
        let metadata = fs::metadata(path)?;

        // 获取文件大小
        let file_size = metadata.len();

        // 生成一个唯一的文件 ID（这里使用一个简单的哈希方法）
        let file_id = FileManager::generate_file_id(file_path);

        Ok(FileMeta {
            file_id,
            file_name,
            file_size,
        })
    }

    // 辅助函数：生成文件 ID
    fn generate_file_id(file_path: &str) -> u32 {
        use std::collections::hash_map::DefaultHasher;
        use std::hash::{Hash, Hasher};

        let mut hasher = DefaultHasher::new();
        file_path.hash(&mut hasher);
        hasher.finish() as u32
    }
}
